import React,{ useEffect, useState } from 'react'
// 引入 antd 组件库组件
import { Layout, Menu } from 'antd'
// 引入 antd 组件图标
import {
  HomeOutlined,
  AppstoreOutlined,
  UserOutlined,
  SettingOutlined,
  TeamOutlined,
  UsergroupAddOutlined,
  CopyOutlined,
  FormOutlined,
  DeleteOutlined,
  BarsOutlined,
  SolutionOutlined,
  ReadOutlined,
  ProfileOutlined,
  ToolOutlined,
  ExclamationCircleOutlined,
  CheckCircleOutlined,
  CloseCircleOutlined
} from '@ant-design/icons';
// 引入样式
import './SideMenu.css'
// withRouter 用于将组件转换为高阶组件
import { withRouter } from 'react-router-dom';
import axios from 'axios'
// connect 函数用于将 组件 和 Redux Store仓库 连接起来
import { connect } from 'react-redux'
// Sider 组件是从 Layout 组件中解构出来的
const { Sider } = Layout;

// 模拟侧边栏菜单项数组，只要把这个数组设置为 Menu 组件的 items属性，Menu 组件就会生成对应的菜单栏
/* const menuList = [
  {
    key: "/home", // 这个 key 用于标识当前菜单项，为了方便，将 key值 设置为这个菜单项点击后要显示的组件对应的路由路径
    label: "首页",  // 菜单项对应的的标题
    icon: <UserOutlined/> // 菜单项对应的图标组件
  },
  {
    key: "/user-manage",  // 由于这是一个下拉菜单项，点击后只是展开下拉菜单，所以这里要设置一个无效的路由路径
    label: "用户管理",
    icon: <UserOutlined/>,
    children: [   // 用于设置下拉菜单项
      {
        key: "/user-manage/list",
        label: "用户列表",
        icon: <UserOutlined/>,
      }
    ]
  },
  {
    key: "/right-manage",
    label: "权限管理",
    icon: <UserOutlined/>,
    children: [
      {
        key: "/right-manage/rightList",
        label: "权限列表",
        icon: <UserOutlined/>,
      },
      {
        key: "/right-manage/roleList",
        label: "角色列表",
        icon: <UserOutlined/>,
      }
    ]
  }
] */

function SideMenu(props) {

  // 从本地存储的 token 中将 role 解构出来，再从 role 中将 rights 解构出来，这个 rights 存储的是当前这个用户可以访问的侧边栏菜单项的key值
  let { role: { rights } } = JSON.parse(localStorage.getItem("token"))

  // 存储侧边菜单项的数据
  const [menu,setMenu] = useState([])

  // 每当当前组件渲染完毕的时候，就会执行这个钩子中的函数
  useEffect(()=>{
    // 获取侧边栏菜单项的数据的接口
    axios.get("http://localhost:5000/rights?_embed=children").then((res)=>{
      // console.log(res);
      // 利用 checkPagePermission 方法将获取到的数据 res.data 处理成合适的形式再赋值给 menu属性
      setMenu(checkPagePermission(res.data))
    })
  },[]) // 第二个参数为空数组，说明当前这个钩子没有依赖项。依赖项就会被监听的值，当被监听的值改变后，这个钩子中的函数也会执行

  // 传入对应的参数，返回一个对象，对象中装的是对应的属性
  const MenuObj = (key, icon, label, children) => {
    return {
      key,
      icon,
      label,
      children,
    }
  }

  // 图标列表，根据菜单项元素的key值获取对应的图标组件
  const iconList = {
    "/home": <HomeOutlined />,
    "/user-manage": <AppstoreOutlined />,
    "/user-manage/list": <UserOutlined />,
    "/right-manage": <SettingOutlined />,
    "/right-manage/role/list": <TeamOutlined />,
    "/right-manage/right/list": <UsergroupAddOutlined />,
    "/news-manage": <CopyOutlined />,
    "/news-manage/add": <FormOutlined />,
    "/news-manage/draft": <DeleteOutlined />,
    "/news-manage/category": <BarsOutlined />,
    "/audit-manage": <SolutionOutlined />,
    "/audit-manage/audit": <ReadOutlined />,
    "/audit-manage/list": <ProfileOutlined />,
    "/publish-manage": <ToolOutlined />,
    "/publish-manage/unpublished": <ExclamationCircleOutlined />,
    "/publish-manage/published": <CheckCircleOutlined />,
    "/publish-manage/sunset": <CloseCircleOutlined />
  }

  const checkPagePermission = (list) => {
    const itemsArr = []
    // 利用 map 方法遍历请求侧边栏菜单项接口返回的数据
    list.map((item) => {
      // 如果当前遍历的元素有children元素，并且长度不为0，说明当前这个元素对应的是一个下拉菜单项
      // rights 存储的是当前这个用户可以访问的侧边栏菜单项的key值，这里用includes方法再rights中查找是否存在当前这个key值，如果存在，证明当前这个用户可以访问这个key对应的侧边栏菜单项，如果不存在，则证明不可以访问，那么这个菜单项就没有存在的必要
      if (item.children && item.children.length !== 0  && rights.includes(item.key)) {
        // map方法中的return的内容将作为新值代替数组遍历到的旧值item
        return itemsArr.push(
          // iconList[item.key] 可以根据当前遍历的元素的key值得到对应的图标组件
          // checkPagePermission(item.children) 因为当前遍历的元素拥有children属性，所以将当前children属性作为参数传递给checkPagePermission方法做二次遍历
          // 下面是将数据传递给 MenuObj 方法，它会根据数据返回一个对象，再将这个对象添加到 itemsArr 数组中
          MenuObj(item.key, iconList[item.key], item.label, checkPagePermission(item.children))
        )
      } else {
        // 这里是items元素没有children属性
        return (
          item.pagepermisson && rights.includes(item.key) &&
          itemsArr.push(MenuObj(item.key, iconList[item.key], item.label))
        )
      }
    })
    return itemsArr
  }

  // 定义一个变量用于存储当前的路由路径
  const SelectedKey = [props.location.pathname]
  // 定义一个变量用于存储要展开的下拉菜单项的key值(也是当前的路由路径)
  // 因为点击的是下拉菜单项，当前路由路径是具体的包含了下拉菜单项对应的key值，而defaultOpenKeys需要的是下拉菜单表头对应的key值
  // 例如： /user-manage/list 是下拉菜单下一个菜单项的key值，也是当前的路由路径，而 /user-manage 才是下拉菜单的key值，defaultOpenKeys需要的是下拉菜单的key值，所以下面要截取一下
  const OpenKeys = ["/" + props.location.pathname.split("/")[1]]

  // 侧边栏菜单项的点击事件回调
  const goToRoute = (e)=>{
    // 只有当当前组件用 withRouter 转换为高阶组件的时候，props中才会有用于操作路由路径的方法
    // 当点击了菜单项后，将菜单项身上是key属性作为路由路径，然后跳转到该路由
    props.history.push(e.key)
  }

  return (
    <Sider
      trigger={null}
      collapsible 
      // collapsed 属性决定Sider组件是否折叠，如果值为true，那么就折叠，反之则不折叠
      // 这里是将collapsed值设置为CollapsedReducer仓库的isCollapsed属性
      collapsed={props.isCollapsed}
    >
      <div className="navigation">
        <div className="logo">全球新闻发布管理系统</div>
        <div style={{flex:1, "overflow":"auto"}}>
          {/* 
            theme 用于设置菜单栏主题，也就是样式风格
            mode 用于设置菜单栏的布局模式
            defaultSelectedKeys 是设置默认高亮选中的侧边栏菜单选项，它的属性值是一个数组，数组中装的是指定菜单项组件的 key 值，下面是将SelectedKey(里面存储的是当前的路由路径)设置为它的属性值，因为侧边菜单项的key值就是一个路由路径，点击菜单项后跳转路由路径，所以当前路由路径也就是对应的侧边菜单项的key值
            selectedKeys 的作用和 defaultSelectedKeys 一样，不过前者是让当前这个组件变成受控组件(也就是当selectedKeys的属性值发生变化的时候，这个组件也要重新渲染，发生变化)，后者不是
            defaultOpenKeys 是设置下拉菜单项是否展开，值为一个数组，数组中存储的是要展开的下拉菜单项的key属性值
            items 用于设置菜单项，值为一个数组，它会根据数组中的元素遍历出菜单项
            onClick 是给遍历出来的菜单项都绑定一个点击事件
          */}
          <Menu
            style={{
              width: "100%",
              fontSize: "16px"
            }}
            theme="dark"
            mode="inline"
            selectedKeys={SelectedKey}
            defaultOpenKeys={OpenKeys}
            items={menu}
            onClick={goToRoute}
          />
        </div>
      </div>
    </Sider>
  )
}

// connect 函数是 React Redux 库提供的用于创建和连接容器组件的函数。它接收两个参数：mapStateToProps 和 mapDispatchToProps。通过 connect 函数，组件可以访问 Redux Store 中的状态并触发对应的 Action
/* 
    connect(
      mapStateToProps     // mapStateToProps 用于将 Redux Store 中的状态映射到当前组件的属性上
      mapDispatchToProps
    )(被包装的组件)
*/
// mapStateToProps接收一个reducer作为参数对象，下面是将 CollapsedReducer 中的 isCollapsed 解构出来
const mapStateToProps = ({CollapsedReducer:{isCollapsed}})=>{
  // 将 isCollapsed 返回出去，这样当前这个组件就可以通过 props 获取到这个 isCollapsed 属性
  return {
    isCollapsed
  }
}
// withRouter 可以将一个普通的组件转换为 高阶组件
export default connect(mapStateToProps)(withRouter(SideMenu)) // 将 SideMenu 转换为 高阶组件，这样 SideMenu 中的props就可以拿到处理路由的方法